home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / haeberli / libgutil / objop.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  16KB  |  817 lines

  1. /*
  2.  * Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*
  18.  *    objop -
  19.  *        Some operations on geometric objects.
  20.  *
  21.  *                Paul Haeberli - 1987
  22.  */
  23. #include "obj.h"
  24. #include "port.h"
  25. #include "texture.h"
  26.  
  27. typedef struct hashvert {
  28.     struct hashvert *next;
  29.     float x, y, z;
  30.     float nx, ny, nz;
  31. } hashvert;
  32.  
  33. static hashvert *newhashvert();
  34. static hashpoint();
  35. static resolvehash();
  36. static setnormal();
  37. static endhash();
  38. static shadeobj();
  39. static swizzle();
  40. static linetouches();
  41.  
  42. objnormal(obj,nx,ny,nz)
  43. object *obj;
  44. float *nx, *ny, *nz;
  45. {
  46.     point *v1, *v2;
  47.     float tx, ty, tz;
  48.     double Xj, Yj, Zj;
  49.     double Xi, Yi, Zi;
  50.     float mag;
  51.  
  52. /* find the normal vector */
  53.  
  54.     v1 = obj->points;
  55.     v2 = v1->next;
  56.     if(!v2)
  57.        return 0;
  58.     Xj = v1->x;
  59.     Yj = v1->y;
  60.     Zj = v1->z;
  61.     tx = ty = tz = 0.0;
  62.     do {
  63.     Xi = Xj; Xj = v2->x;
  64.     Yi = Yj; Yj = v2->y;
  65.     Zi = Zj; Zj = v2->z;
  66.     tx += (Yi - Yj) * (Zi + Zj);
  67.     ty += (Zi - Zj) * (Xi + Xj);
  68.     tz += (Xi - Xj) * (Yi + Yj);
  69.     v1 = v2; 
  70.     v2 = v2->next;
  71.     if(v2 == 0)
  72.         v2 = obj->points;
  73.     } while( v1 != obj->points );
  74.     
  75. /* normalize the facet normal */
  76.  
  77.     mag = sqrt(tx*tx + ty*ty + tz*tz);
  78.     if( mag < 0.00001 ) {
  79.     *nx = 0.0;
  80.     *ny = 0.0;
  81.     *nz = 0.0;
  82.     } else {
  83.     *nx = tx/mag;;
  84.     *ny = ty/mag;;
  85.     *nz = tz/mag;;
  86.     }
  87. }
  88.  
  89. printobj(obj)
  90. object *obj;
  91. {
  92.     point *apnt;
  93.  
  94.     while(obj) {
  95.     if(obj->points != NULL) {
  96.         if(obj->type == OBJ_POINTS) {
  97.         printf("type points\n");
  98.         while(apnt) {
  99.            printf("[%f %f %f] ",apnt->x,apnt->y,apnt->z);
  100.            apnt = apnt->next;
  101.         }
  102.             printf("\n");
  103.         } else if(obj->type == OBJ_LINE) {
  104.         printf("type line\n");
  105.         apnt = obj->points;
  106.         while(apnt) {
  107.            printf("[%f %f %f] ",apnt->x,apnt->y,apnt->z);
  108.            apnt = apnt->next;
  109.         }
  110.            printf("\n");
  111.            printf("\n");
  112.         } else if(obj->type == OBJ_LOOP) {
  113.         printf("type loop\n");
  114.         apnt = obj->points;
  115.         while(apnt) {
  116.            printf("[%f %f %f] ",apnt->x,apnt->y,apnt->z);
  117.            apnt = apnt->next;
  118.         }
  119.            printf("\n");
  120.            printf("\n");
  121.         } else if(obj->type == OBJ_POLYGON) {
  122.         printf("type poly\n");
  123.         apnt = obj->points;
  124.         while(apnt) {
  125.            printf("[%f %f %f] ",apnt->x,apnt->y,apnt->z);
  126.            apnt = apnt->next;
  127.         }
  128.            printf("\n");
  129.         } else 
  130.         printf("printobj: blat\n");
  131.     }
  132.     obj = obj->next;
  133.     }
  134. }
  135.  
  136. /*
  137.  *    Derive normals from geometry.
  138.  *
  139.  */
  140. #define HASHSIZE        512
  141. #define HASHFUNC(x,y,z)        (((int)((x+y+z) * 30023.32)) & (HASHSIZE-1))
  142.  
  143. static hashvert *hashtab[HASHSIZE];
  144.  
  145. static hashvert *newhashvert()
  146. {
  147.     return (hashvert *)mymalloc(sizeof(hashvert));
  148. }
  149.  
  150. /*
  151.  *    applynormals - 
  152.  *        Put normals onto an object.
  153.  *
  154.  */
  155. applynormals(nobj,smoothness)
  156. object *nobj;
  157. float smoothness;
  158. {
  159.     object *obj;
  160.     point *pnt;
  161.     float nx, ny, nz;
  162.  
  163.     if(smoothness < 0.005) {
  164.     obj = nobj;
  165.     while(obj) {
  166.         if(obj->points) {
  167.         objnormal(obj,&nx,&ny,&nz);
  168.         if(!obj->attr) 
  169.            obj->attr = newattr();
  170.         obj->attr->nx = nx;
  171.         obj->attr->ny = ny;
  172.         obj->attr->nz = nz;
  173.         }
  174.         obj = obj->next;
  175.     }
  176.     } else { 
  177.     obj = nobj;
  178.  
  179. /* add all the points to the hash table */
  180.     while(obj) {
  181.         if(obj->points) {
  182.         objnormal(obj,&nx,&ny,&nz);
  183.         if(!obj->attr) 
  184.            obj->attr = newattr();
  185.         obj->attr->nx = nx;
  186.         obj->attr->ny = ny;
  187.         obj->attr->nz = nz;
  188.         pnt = obj->points;
  189.         while(pnt) {
  190.             hashpoint(pnt,obj->attr);
  191.             pnt = pnt->next;
  192.         }
  193.         }
  194.         obj = obj->next;
  195.     }
  196.  
  197. /* normalize all the vertex normals */
  198.     resolvehash();
  199.  
  200. /* set the vertex normal based on the smoothness desired */
  201.     obj = nobj;
  202.     while(obj) {
  203.         if(obj->points) {
  204.         pnt = obj->points;
  205.         while(pnt) {
  206.             setnormal(pnt,obj->attr,smoothness);
  207.             pnt = pnt->next;
  208.         }
  209.         }
  210.         obj = obj->next;
  211.     }
  212.  
  213. /* free the vert structures */
  214.     endhash();
  215.     }
  216. }
  217.  
  218. static hashpoint(pnt,attr) 
  219. point *pnt;
  220. attribs *attr;
  221. {
  222.     int pos;
  223.     hashvert *vptr;
  224.  
  225.     pos = HASHFUNC(pnt->x,pnt->y,pnt->z);
  226.     vptr = hashtab[pos];
  227.     while(vptr) {
  228.     if( (vptr->x == pnt->x)  && 
  229.              (vptr->y == pnt->y)  && (vptr->z == pnt->z) ) {
  230.         vptr->nx += attr->nx;
  231.         vptr->ny += attr->ny;
  232.         vptr->nz += attr->nz;
  233.         return;
  234.     }
  235.     vptr = vptr->next;
  236.     }
  237.     vptr = newhashvert();
  238.     vptr->x = pnt->x;
  239.     vptr->y = pnt->y;
  240.     vptr->z = pnt->z;
  241.     vptr->nx = attr->nx;
  242.     vptr->ny = attr->ny;
  243.     vptr->nz = attr->nz;
  244.     vptr->next = hashtab[pos];
  245.     hashtab[pos] = vptr;
  246. }
  247.  
  248. static resolvehash()
  249. {
  250.     int i;
  251.     hashvert *vptr;
  252.     float mag;
  253.  
  254.     for(i=0; i<HASHSIZE; i++) {
  255.     vptr = hashtab[i];
  256.     while(vptr) {
  257.         mag = sqrt(vptr->nx*vptr->nx+vptr->ny*vptr->ny+vptr->nz*vptr->nz);
  258.         vptr->nx /= mag;
  259.         vptr->ny /= mag;
  260.         vptr->nz /= mag;
  261.         vptr = vptr->next;
  262.     }
  263.     }
  264. }
  265.  
  266. static setnormal(pnt,attr,smoothness)
  267. point *pnt;
  268. attribs *attr;
  269. float smoothness;
  270. {
  271.     int pos;
  272.     hashvert *vptr;
  273.     float dot;
  274.  
  275.     pos = HASHFUNC(pnt->x,pnt->y,pnt->z);
  276.     vptr = hashtab[pos];
  277.     while(vptr) {
  278.     if( (vptr->x == pnt->x)  && 
  279.              (vptr->y == pnt->y)  && (vptr->z == pnt->z) ) {
  280.         if(!pnt->attr)
  281.         pnt->attr = newattr();
  282.         dot = vptr->nx*attr->nx+vptr->ny*attr->ny+vptr->nz*attr->nz;
  283.         if(dot<0.0)
  284.         dot = 0.0;
  285.         if(dot>(1.0-smoothness)) {
  286.         pnt->attr->nx = vptr->nx;
  287.         pnt->attr->ny = vptr->ny;
  288.         pnt->attr->nz = vptr->nz;
  289.         } else {
  290.         pnt->attr->nx = attr->nx;
  291.         pnt->attr->ny = attr->ny;
  292.         pnt->attr->nz = attr->nz;
  293.         }
  294.         return;
  295.     }
  296.     vptr = vptr->next;
  297.     }
  298.     printf("setnormal: bad poop\n");
  299. }
  300.  
  301. static endhash()
  302. {
  303.     int i;
  304.     hashvert *vptr, *nptr;
  305.     float mag;
  306.  
  307.     for(i=0; i<HASHSIZE; i++) {
  308.     vptr = hashtab[i];
  309.     while(vptr) {
  310.         nptr = vptr->next;
  311.         free(vptr);
  312.         vptr = nptr;
  313.     }
  314.     hashtab[i] = 0;
  315.     }
  316. }
  317.  
  318. static float ix, iy, iz;
  319. static TEXTURE *env;
  320.  
  321. /*
  322.  *    setlight - 
  323.  *        Set the position of a single light source.
  324.  *
  325.  */
  326. setlight(x,y,z)
  327. float x, y, z;
  328. {
  329.     float mag;
  330.  
  331.     mag = sqrt(x*x+y*y+z*z);
  332.     ix = x/mag;
  333.     iy = y/mag;
  334.     iz = z/mag;
  335. }
  336.  
  337. setenviron(envname)
  338. char *envname;
  339. {
  340.     env = tmopen(envname);
  341. }
  342.  
  343. /*
  344.  *    lightobj - 
  345.  *        Illuminate an object.
  346.  *
  347.  */
  348. lightobj(obj)
  349. object *obj;
  350. {
  351.     int s;
  352.  
  353.     if(!hasnormals(obj))
  354.     applynormals(obj,0.0);
  355.     while(obj) {
  356.     if(obj->type == OBJ_POLYGON) 
  357.         shadeobj(obj);
  358.     obj=obj->next;
  359.     }
  360. }
  361.  
  362. /*
  363.  *    vertexlightobj - 
  364.  *        Illuminate an object at verticies.
  365.  *
  366.  */
  367. vertexlightobj(obj,smoothness)
  368. object *obj;
  369. float smoothness;
  370. {
  371.     point *pnt;
  372.  
  373.     /*if(!hasnormals(obj)) */
  374.     applynormals(obj,smoothness);
  375.     while(obj) {
  376.     if(obj->type == OBJ_POLYGON) {
  377.         shadeobj(obj);
  378.         pnt = obj->points;
  379.         while(pnt) {
  380.         shadeattr(pnt->attr);
  381.         pnt = pnt->next;
  382.         }
  383.     }
  384.     obj=obj->next;
  385.     }
  386. }
  387.  
  388. static shadeobj(obj)
  389. object *obj;
  390. {
  391.     shadeattr(obj->attr);
  392. }
  393.  
  394. shadeattr(attr)
  395. attribs *attr;
  396. {
  397.     float dot;
  398.     vect p, c;
  399.  
  400.     if(env) {
  401.     p.x = attr->nx;
  402.     p.y = attr->ny;
  403.     p.z = attr->nz;
  404.     lookx(&p);
  405.     envsample(env,&p,&c);
  406.     dot = c.x;
  407.     } else {
  408.     dot = ix*attr->nx + iy*attr->ny + iz*attr->nz;
  409.     dot = (dot+1.0)/2.0;
  410.     }
  411.     attr->r = 128+(127*dot);
  412. }
  413.  
  414. /*
  415.  *    hasnormals - 
  416.  *        Returns true if normals the object already has normals.
  417.  *
  418.  */
  419. hasnormals(obj)
  420. object *obj;
  421. {
  422.     if(!obj->attr)
  423.     return 0;
  424.     else if( (obj->attr->nx == 0.0) && 
  425.          (obj->attr->ny == 0.0) && (obj->attr->nz == 0.0) )
  426.     return 0;
  427.     else
  428.     return 1;
  429. }
  430.  
  431.  
  432. /*
  433.  *    triarea - 
  434.  *        Return the area of a triangle of points. 
  435.  *
  436.  */
  437. float triarea(p1,p2,p3)
  438. point *p1, *p2, *p3;
  439. {
  440.     double area;
  441.  
  442.     area  = (p1->x-p3->x)*(p1->y+p3->y);
  443.     area += (p3->x-p2->x)*(p3->y+p2->y);
  444.     area += (p2->x-p1->x)*(p2->y+p1->y);
  445.     return area/2.0;
  446. }
  447.  
  448. #define PREV(p)        ((p-1+npoints)%npoints)
  449. #define NEXT(p)        ((p+1)%npoints)
  450. #define NOTBAD         (-1)
  451.  
  452. #define XPLANE    1
  453. #define YPLANE    2
  454. #define ZPLANE    3
  455.  
  456. static swizzle( obj )
  457. object *obj;
  458. {
  459.     int sign, dir;
  460.     point *pnt;
  461.     float temp;
  462.     float tx, ty, tz;
  463.  
  464. /* determine which plane to project the polygon onto */
  465.     objnormal(obj,&tx,&ty,&tz);
  466.     dir = ZPLANE;
  467.     sign = -1;
  468.     if( (ABS(tx) > ABS(ty)) && (ABS(tx) > ABS(tz)) ) {
  469.     dir = XPLANE;
  470.     if(tx>0.0) sign = 1;
  471.     } else if( (ABS(ty) > ABS(tx)) && (ABS(ty) > ABS(tz)) ) {
  472.     dir = YPLANE;
  473.     if(ty>0.0) sign = 1;
  474.     } else if( (ABS(tz) > ABS(tx)) && (ABS(tz) > ABS(ty)) ) {
  475.     dir = ZPLANE;
  476.     if(tz>0.0) sign = 1;
  477.     }
  478.  
  479. /* project the polygon onto the plane */
  480.     pnt = obj->points;
  481.     switch(dir) {
  482.     case XPLANE:
  483.         while(pnt) {
  484.         temp = pnt->x;
  485.         pnt->x = pnt->y;
  486.         pnt->y = pnt->z;
  487.         pnt->z = temp;
  488.         pnt = pnt->next;
  489.         }
  490.         break;
  491.     case YPLANE:
  492.         while(pnt) {
  493.         temp = pnt->z;
  494.         pnt->z = pnt->y;
  495.         pnt->y = pnt->x;
  496.         pnt->x = temp;
  497.         pnt = pnt->next;
  498.         }
  499.         break;
  500.     }
  501.     return (sign*dir);
  502. }
  503.  
  504. unswizzle( obj, dir )
  505. object *obj;
  506. int dir;
  507. {
  508.     point *pnt;
  509.     float temp;
  510.  
  511.     if(dir<0)
  512.     dir = -dir;
  513.  
  514. /* unproject the polygon from the plane */
  515.     pnt = obj->points;
  516.     switch(dir) {
  517.     case XPLANE:
  518.         while(pnt) {
  519.         temp = pnt->z;
  520.         pnt->z = pnt->y;
  521.         pnt->y = pnt->x;
  522.         pnt->x = temp;
  523.         pnt = pnt->next;
  524.         }
  525.         break;
  526.     case YPLANE:
  527.         while(pnt) {
  528.         temp = pnt->x;
  529.         pnt->x = pnt->y;
  530.         pnt->y = pnt->z;
  531.         pnt->z = temp;
  532.         pnt = pnt->next;
  533.         }
  534.         break;
  535.     }
  536.     
  537. }
  538.  
  539. /*
  540.  *    toconvex -
  541.  *        Make all the polygons in an object convex.
  542.  *
  543.  */
  544. toconvex(obj)
  545. object *obj;
  546. {
  547.     object *nextobj, *tobj;
  548.     object *obj1, *obj2;
  549.     point *pnt, *pntlist, **w;
  550.     int i, pos, npoints;
  551.     int split, badone, deltasplit;
  552.     int s;
  553.  
  554.     while(obj) {
  555.     nextobj = obj->next;
  556.     if(obj->type == OBJ_POLYGON) {
  557.         if(obj->points) {
  558.  
  559. /* count the points */
  560.         npoints = 0;
  561.         pnt = obj->points;
  562.         while(pnt) {
  563.             npoints++;
  564.             pnt = pnt->next;
  565.         }
  566.         if(npoints>3) {
  567.             w = (point **)mymalloc((2+npoints)*sizeof(point *));
  568.  
  569. /* get pointers into a linear array */
  570.             i = 0;
  571.             pnt = obj->points;
  572.             while(pnt) {
  573.             w[i++] = pnt;
  574.             pnt = pnt->next;
  575.             }
  576.             w[npoints] = w[0];
  577.             w[npoints+1] = w[1];
  578.  
  579. /* see if this poly is a bad one */
  580.             s = swizzle(obj);
  581.             badone = NOTBAD;
  582.             for(i=0; i<npoints; i++) {
  583.             if(!w[i+2]) {
  584.                 printf("what1\n");
  585.             }
  586.             if((s*triarea(w[i+0],w[i+1],w[i+2])) > 0.0) {
  587.                 badone = NEXT(i);
  588.                 break;
  589.             }
  590.             }
  591. /*
  592.  *    find a point that can be seen from the bad point.  This is done
  593.  *    on a cheezy way right now.  Make it do binary subdivision
  594.  *    sometime. 
  595.  */
  596.             if(badone != NOTBAD) {
  597.             split = (badone+(3*npoints/2))%npoints;
  598.             deltasplit = 1;
  599.             for(pos=3; pos<npoints; pos++) {
  600.  
  601. /* if the line doesn't touch then split along it */
  602.                 if(!w[split]) {
  603.                 printf("what2\n");
  604.                 printf("npoints %d split is %d\n",npoints,split);
  605.                 }
  606.                 if((s*triarea(w[badone],w[badone+1],w[split]))< 0.0 &&
  607.                     !linetouches(w[badone],w[split],obj)) {
  608.  
  609. /* unlink into a single ring of verts */
  610.                 obj->next = 0;
  611.  
  612. /* arrange the badone to be the first vertex in the list */
  613.                 if(badone != 0) {
  614.                     w[badone-1]->next = 0;
  615.                     w[npoints-1]->next = w[0];
  616.                     obj->points = w[badone];
  617.                 }
  618.  
  619. /* clone the object header, but not the point list. Make obj1 and obj2 */
  620.                 obj1 = obj;
  621.                 pntlist = obj1->points;
  622.                 obj1->points = 0;
  623.                 obj2 = cloneobj(obj);
  624.                 obj1->points = pntlist;
  625.  
  626. /* step on down n points and clone the last point */
  627.                 pnt = obj1->points;
  628.                 pntlist = w[split];
  629.                 w[PREV(split)]->next = clonepnt(w[split]);
  630.  
  631. /* clone the other point and link in the other part */
  632.                 obj2->points = clonepnt(obj1->points);
  633.                 obj2->points->next = pntlist;
  634.  
  635. /* make the first ring convex */
  636.                 toconvex(obj1);
  637.  
  638. /* make the last ring in this list point to object 2 */
  639.                 for(tobj = obj1; tobj->next; tobj = tobj->next)
  640.                     ;
  641.                 tobj->next = obj2;
  642.  
  643. /* make the second ring convex */
  644.                 toconvex(obj2);
  645.  
  646. /* make the last ring in this list point to the next object */
  647.                 for(tobj = obj2; tobj->next; tobj = tobj->next)
  648.                     ;
  649.                 tobj->next = nextobj;
  650.                 break;
  651.                 }
  652.                 split += deltasplit;
  653.                 split = (split+npoints)%npoints;
  654.                 if(deltasplit>0)
  655.                 deltasplit = -deltasplit-1;
  656.                 else
  657.                 deltasplit = -deltasplit+1;
  658.             }
  659.             if(pos==npoints) 
  660.                 fprintf(stderr,"toconvex: bad poop\n");
  661.             }
  662.             unswizzle(obj,s);
  663.             free(w);
  664.         }
  665.         }
  666.     }
  667.     obj = nextobj;
  668.     }
  669. }
  670.  
  671. static linetouches(p1,p2,obj)
  672. point *p1, *p2;
  673. object *obj;
  674. {
  675.     point *pnt, *npnt;
  676.     float v1, v2;
  677.  
  678.     pnt = obj->points;
  679.     npnt = pnt->next;
  680.     while(pnt) {
  681.     v1 = triarea(p1,p2,pnt) * triarea(p1,p2,npnt);
  682.     v2 = triarea(pnt,npnt,p1) * triarea(pnt,npnt,p2);
  683.     if((v1<0.0) && (v2<0.0)) 
  684.         return 1;
  685.     pnt = pnt->next;
  686.     npnt = npnt->next;
  687.     if(!npnt)
  688.         npnt = obj->points;
  689.     }
  690.     return 0;
  691. }
  692.  
  693. #define MAXPOINTS    100
  694. static point **toquadwork;
  695.  
  696. /*
  697.  *    toquads -
  698.  *        Make all the polygons in an object quadralaterals - 
  699.  *    even triangles.
  700.  *
  701.  */
  702. toquads(obj)
  703. object *obj;
  704. {
  705.     object *nobj, *nextobj;
  706.     point *pnt, *fpnt;
  707.     point *pntlist;
  708.     int i, npoints, npolys;
  709.     int left, right;
  710.  
  711.     if(!toquadwork)
  712.     toquadwork = (point **)mymalloc(MAXPOINTS*sizeof(point *));
  713.     while(obj) {
  714.     nextobj = obj->next;
  715.     if(obj->type == OBJ_POLYGON) {
  716.         if(obj->points) {
  717.         npoints = 0;
  718.         fpnt = obj->points;
  719.         while(fpnt) {
  720.             toquadwork[npoints++] = fpnt;
  721.             fpnt = fpnt->next;
  722.         }
  723.         if(npoints>MAXPOINTS) {
  724.             fprintf(stderr,"toquads: polygon too big\n");
  725.             exit(1);
  726.         }
  727.         if(npoints != 4) {
  728.             if(npoints<3) {
  729.             freepnts(obj->points);
  730.             obj->points = 0;
  731.             } else if(npoints == 3) {
  732.             pnt = clonepnt(obj->points);
  733.             pnt->next = obj->points;
  734.             obj->points = pnt;
  735.             } else {
  736.             npolys = (npoints-1)/2;
  737.             left = 0;
  738.             right = 1;
  739.             pntlist = obj->points;
  740.             obj->points = 0;
  741.             if(npoints & 1) {
  742.                 pnt = clonepnt(toquadwork[right]);
  743.                 pnt->next = obj->points;
  744.                 obj->points = pnt;
  745.  
  746.                 pnt = clonepnt(toquadwork[right]);
  747.                 pnt->next = obj->points;
  748.                 obj->points = pnt;
  749.  
  750.                 pnt = clonepnt(toquadwork[left]);
  751.                 pnt->next = obj->points;
  752.                 obj->points = pnt;
  753.  
  754.                 pnt = clonepnt(toquadwork[PREV(left)]);
  755.                 pnt->next = obj->points;
  756.                 obj->points = pnt;
  757.  
  758.                 left = PREV(left);
  759.             } else {
  760.                 pnt = clonepnt(toquadwork[NEXT(right)]);
  761.                 pnt->next = obj->points;
  762.                 obj->points = pnt;
  763.                 pnt = clonepnt(toquadwork[right]);
  764.                 pnt->next = obj->points;
  765.                 obj->points = pnt;
  766.                 pnt = clonepnt(toquadwork[left]);
  767.                 pnt->next = obj->points;
  768.                 obj->points = pnt;
  769.                 pnt = clonepnt(toquadwork[PREV(left)]);
  770.                 pnt->next = obj->points;
  771.                 obj->points = pnt;
  772.                 left = PREV(left);
  773.                 right = NEXT(right);
  774.             }
  775.              npolys--;
  776.             for(i=0; i<npolys; i++) {
  777.                 nobj = newobj(); 
  778.                 nobj->type = OBJ_POLYGON;
  779.                 if(obj->attr)
  780.                 nobj->attr = cloneattr(obj->attr);
  781.                 pnt = clonepnt(toquadwork[NEXT(right)]);
  782.                 pnt->next = nobj->points;
  783.                 nobj->points = pnt;
  784.                 pnt = clonepnt(toquadwork[right]);
  785.                 pnt->next = nobj->points;
  786.                 nobj->points = pnt;
  787.                 pnt = clonepnt(toquadwork[left]);
  788.                 pnt->next = nobj->points;
  789.                 nobj->points = pnt;
  790.                 pnt = clonepnt(toquadwork[PREV(left)]);
  791.                 pnt->next = nobj->points;
  792.                 nobj->points = pnt;
  793.                 nobj->next = obj->next;
  794.                 obj->next = nobj;
  795.                 left = PREV(left);
  796.                 right = NEXT(right);
  797.             }
  798.             freepnts(pntlist);
  799.             }
  800.         }
  801.         }
  802.     }
  803.     obj = nextobj;
  804.     }
  805. }
  806.  
  807. lookx(v)
  808. vect *v;
  809. {
  810.     float temp;
  811.  
  812.     temp = v->z;    /* to make us look down the x axis */
  813.     v->z = v->y;
  814.     v->y = -v->x;
  815.     v->x = temp;
  816. }
  817.